/*****************************
 *@file: AlgUtil
 *@author: 陈吕唐
 *@desc: 常用算法工具类
 *@date: 2024-02-29	10:43
 *****************************/
export default class AlgUtil {

    /**
     * 随机打乱数组 (洗牌算法)
     * @param array 原数组
     * @returns {T[]} 洗牌后数组
     */
    static shuffleArray<T>(array: readonly T[]): T[] {
        const copy = [...array];
        for (let i = copy.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [copy[i], copy[j]] = [copy[j], copy[i]];
        }
        return copy;
    }


    /**
     * 从数组中随机取count个不重复的元素
     * @param array 可选数组
     * @param count 选取数量
     * @returns 
     */
    static pickRandomUniqueItems<T>(array: readonly T[], count: number): T[] {

        if (count > array.length) {
            throw new Error('Cannot pick more items than the array length');
        }

        if (count == array.length) {
            return [...array];
        }

        let shuffleArray = AlgUtil.shuffleArray(array);
        return shuffleArray.slice(0, count);
    }


    /**
     * 从数组中根据权重随机取1个元素
     * @param array 可选数组
     * @param weight 权重数组
     * @returns 
     */
    static pickRandomItemByWeight<T>(array: T[], weight: number[]): T {

        if (array.length == 0) {
            throw new Error('Array length must be greater than 0');
        }


        if (array.length != weight.length) {
            throw new Error('Array length and weight length must be equal');
        }

        let sum = weight.reduce((a, b) => a + b, 0);

        let random = Math.random() * sum;

        let total = 0;

        for (let i = 0; i < weight.length; i++) {
            total += weight[i];
            if (random <= total) {
                return array[i];
            }
        }

        throw new Error('Random number is out of range');
    }
}